package ioc

import (
	"context"
	"gitee.com/xiao_hange/go-admin-file/file/ioc/config"
	myTrace "gitee.com/xiao_hange/go-admin-pkg/pkg/grpcx/interceptors/trace"
	"github.com/spf13/viper"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/exporters/zipkin"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	"go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
	trace2 "go.opentelemetry.io/otel/trace"
	"time"
)

func InitOTELTracerProvider(ja *config.JaegerConfig) *trace.TracerProvider {
	res, err := newResource("GoAdmin-Grpc-File-Server", "v0.0.1")
	if err != nil {
		panic(err)
	}
	prop := newPropagator()
	otel.SetTextMapPropagator(prop)
	//tp, err := newZipkinProvider(res)
	tp, err := newJeagerProvider(res, ja)
	if err != nil {
		panic(err)
	}
	//trace.SetTracerProvider(tp)
	newTp := &myTrace.MyTracerProvider{
		NopProvider: trace2.NewNoopTracerProvider(),
		Provider:    tp,
		Kind:        trace2.SpanKindServer,
	}
	otel.SetTracerProvider(newTp)
	return tp
}

func InitOTEL(ja *config.JaegerConfig) func(ctx context.Context) {
	tp := InitOTELTracerProvider(ja)
	return func(ctx context.Context) {
		_ = tp.Shutdown(ctx)
	}
}

func newResource(serviceName, serviceVersion string) (*resource.Resource, error) {
	return resource.Merge(
		resource.Default(),
		resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceName(serviceName),
			semconv.ServiceVersion(serviceVersion),
		),
	)
}

func newZipkinProvider(res *resource.Resource) (*trace.TracerProvider, error) {
	addr := viper.GetString("zipkin.addr")
	exporter, err := zipkin.New(addr)
	if err != nil {
		return nil, err
	}
	traceProvider := trace.NewTracerProvider(
		trace.WithBatcher(exporter, trace.WithBatchTimeout(time.Second)),
		trace.WithResource(res),
	)
	return traceProvider, nil
}

func newPropagator() propagation.TextMapPropagator {
	return propagation.NewCompositeTextMapPropagator(
		propagation.TraceContext{},
		propagation.Baggage{},
	)
}

func newJeagerProvider(res *resource.Resource, ja *config.JaegerConfig) (*trace.TracerProvider, error) {
	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(ja.Addr)))
	if err != nil {
		return nil, err
	}
	tp := trace.NewTracerProvider(
		trace.WithBatcher(exp),
		trace.WithResource(res),
	)
	return tp, nil
}
